﻿using System.Net.Sockets;
using System.Threading.Tasks;
using ePipe;
using eTask;
using Letter.Net.Sockets;

namespace Letter.Net.Session;

sealed partial class UdpSession<TSnders> : ASession, IUdpConnected  where TSnders : ASocketSnderProvider<UdpSnder>
{
    public UdpSession(Socket socket, in TransportSettings settings, in UdpSocketOperators<TSnders> socketOperators, AConnection connection)
        : base(socket, settings.memoryPool)
    {
        this.Connection = connection;

        this.SocketRcver = socketOperators.rcver;
        this.SocketSnders = socketOperators.snders;
        
        var input = Pipeline.CreateStandardPipe(settings.inputOptions);
        var output = Pipeline.CreateStandardPipe(settings.outputOptions);
        this.Application = Pipeline.CreateDuplexPipe(output.Reader, input.Writer);
        this.Transport = Pipeline.CreateDuplexPipe(input.Reader, output.Writer);

        this.channelRcver = new UdpSessionRcver(this);
        this.channelSnder = new UdpSessionSnder(this);
    }
    
    private UdpRcver SocketRcver
    {
        get;
    }
    private ASocketSnderProvider<UdpSnder> SocketSnders
    {
        get;
    }

    private IDuplexPipe<byte> Application
    {
        get;
    }

    private AConnection Connection
    {
        get;
    }
    
    public override bool Active
    {
        get { return !this.closed; }
    }
    
    private UdpSessionRcver channelRcver;
    private UdpSessionSnder channelSnder;
    private volatile bool closed = false; 
    
    public override ValueTask StartAsync()
    {
        this.channelRcver.Start();
        this.channelSnder.Start();

        this.Connection.Init(this);
        this.Connection.OnActive();
        
        return ValueTasks.CompletedTask;
    }
    
    public void Connecte()
    {
        this.RemoteEndPoint = this.socket.RemoteEndPoint;
    }
    
    public override async ValueTask CloseAsync()
    {
        if (this.closed)
        {
            return;
        }

        this.closed = true;

        await base.CloseAsync();
        
        await this.channelRcver.CloseAsync();
        await this.channelSnder.CloseAsync();

        this.SocketRcver.Dispose();
        this.SocketSnders.Dispose();
        this.Connection.OnInactive();
    }

    
}
